package maintain

import (
	"context"
	"fmt"
	"gf_blog_admin/internal/service"
	"github.com/gogf/gf/v2/container/garray"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/frame/g"
)

type sDatabase struct{}

func init() {
	service.RegisterDatabase(NewDatabase())
}

func NewDatabase() *sDatabase {
	return &sDatabase{}
}

func (s *sDatabase) List(ctx context.Context) (out []map[string]interface{}, err error) {
	out, err = s.getTables(ctx)
	return
}

func (s *sDatabase) Detail(ctx context.Context, table string) (out []map[string]interface{}, err error) {
	out, err = s.getColumns(ctx, table)
	return
}

func (s *sDatabase) Optimize(ctx context.Context, tables []string) (err error) {
	arr := garray.NewStrArrayFrom(tables, true)
	str := arr.Unique().Join(",")
	_, err = g.DB().Exec(ctx, fmt.Sprintf("OPTIMIZE TABLE %s", str))
	return
}

func (s *sDatabase) Repair(ctx context.Context, tables []string) (err error) {
	arr := garray.NewStrArrayFrom(tables, true)
	str := arr.Unique().Join(",")
	_, err = g.DB().Exec(ctx, fmt.Sprintf("REPAIR TABLE %s", str))
	return
}

func (s *sDatabase) getTables(ctx context.Context) (data []map[string]interface{}, err error) {
	sql := `
SELECT
	table_name AS 'name',
	(data_length + index_length) AS 'size',
	table_comment AS 'comment',
	ENGINE AS 'engine',
	table_collation AS 'collation'
FROM
	information_schema.TABLES
WHERE
    table_schema = '%s' AND table_type IN ('BASE TABLE', 'SYSTEM VERSIONED')
ORDER BY table_name`

	sql, err = gdb.FormatMultiLineSqlToSingle(sql)
	if err != nil {
		return nil, err
	}
	result, err := g.DB().Query(ctx, fmt.Sprintf(sql, g.DB().GetConfig().Name))
	if err != nil {
		return nil, err
	}

	return result.List(), nil
}

func (s *sDatabase) getColumns(ctx context.Context, table string) (data []map[string]interface{}, err error) {
	result, err := g.DB().Query(ctx, fmt.Sprintf(`SHOW FULL COLUMNS FROM %s`, table))
	if err != nil {
		return nil, err
	}

	for _, m := range result {
		data = append(data, map[string]interface{}{
			"name":      m["Field"].String(),
			"type":      m["Type"].String(),
			"nullable":  m["Null"].Bool(),
			"collation": m["Collation"].String(),
			"default":   m["Default"].Val(),
			"extra":     m["Extra"].String(),
			"comment":   m["Comment"].String(),
		})
	}
	return
}
